#pragma once

#include <stdint.h>
#include <cstddef>
#include <cassert>

// array with fixed size, wrap the default c style array
template<typename DataType, size_t Size>
class  TArray
{
public:
    TArray()
        :Data(reinterpret_cast<DataType*>(new uint8_t[sizeof(DataType)*Size]))
    {
    }


    TArray(const TArray& Other)
        :Data(reinterpret_cast<DataType*>(new uint8_t[sizeof(DataType) * Size]))
    {
        for (size_t Index = 0; Index < GetSize(); Index++)
        {
            Data[Index] = Other.Data[Index];
        }
    }

    TArray(const TArray&& Other)
        :Data(Other.Data)
    {
        Other.Data = nullptr;
    }

    TArray& operator = (const TArray& Other)
    {
        assert(Data);

        for (size_t Index = 0; Index < Size; Index++)
        {
            Data[Index] = Other.Data[Index];
        }

        return *this;
    }

    TArray& operator = (TArray&& Other)
    {
        for (size_t Index = 0; Index < Size; Index++)
        {
            (Data + Index)->DataType::~DataType();
        }
        delete[] reinterpret_cast<uint8_t*>(Data);


        Data = Other.Data;
        Other.Data = nullptr;

        return *this;
    }



    ~TArray()
    {
        if (Data) //if Data moved, Data will be nullptr
        {
            for (size_t Index = 0; Index < Size; Index++)
            {
                (Data + Index)->DataType::~DataType();
            }
            delete[] reinterpret_cast<uint8_t*>(Data);
        }
    }

    DataType& operator[](size_t Index)
    {
        assert(Index < Size);
        return Data[Index];
    }

    const DataType& operator[](size_t Index) const
    {
        assert(Index < Size);
        return Data[Index];
    }



    size_t GetSize()
    {
        return Size;
    }
private:



    DataType* Data;// [Size] ;
};